package me.uniauto.common.filter;


import me.uniauto.Constants.HttpConstants;
import me.uniauto.request.ParameterRequestWrapper;
import me.uniauto.util.*;
import me.uniauto.util.cipher.Des3Util;
import me.uniauto.util.cipher.MD5;
import me.uniauto.util.resp.ResponseWrapper;
import net.sf.json.JSONObject;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 该类为参数验证过滤器。 1、取出header和parameter值。
 * 2、header里需要有JSESESSION、did、sign：JSESESSION是shiro生产的session
 * ，did是设备id，sign是参数MD5签名。
 * 3、把header里的did取出，和本地的_key_end拼起来作为加密的key值，放在request的attribute属性里
 * ，key为_cipher_key。 4、取出parameter里的params，进行MD5加密，和header里的sign作比对，一致，说明参数没问题。
 * 5、、、、、、、
 *
 * @author wangkuan
 */
public class CipherArgsCheckFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String swagger = req.getParameter(HttpConstants._swagger_ui);
        if(MyStringUtil.isEmpty(swagger)){
            chain.doFilter(request,response);
        }else{
            this.app(request,response,chain);
        }

    }

    private void app(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        req.setCharacterEncoding(HttpConstants.UTF_8);
        String uri = req.getRequestURI();
        ResponseWrapper resp = new ResponseWrapper((HttpServletResponse) response);
        PrintWriter out = resp.getResponse().getWriter();
        try{
            //首先[文件上传类的url]： excludeUrls是不需要过滤的。不需要加密和解密的url。主要用于文件上传。因为没有did等参数，所以返回是明文的。
            for (String eUrl : HttpConstants._excludeUrls) {
                if (uri.endsWith(eUrl)) {
                    chain.doFilter(req, resp);
                    byte[] resultByte = resp.getResponseData();
                    resp.getResponse().getWriter().print(new String(resultByte, HttpConstants.UTF_8));
                    System.out.println("filter...excludeUrl..{}   " + uri);
                    return;
                }
            }
            /**
             * 获取params
             * 跟sign比较
             * 判断公共参数
             * 将秘钥放入req中
             */
            Map<String,String> hMap= RequestUtil.headerMap(req);
            Map pMap=RequestUtil.paramsMap(req);
            String params= (String) pMap.get(HttpConstants._params);
            String headerSign=hMap.get(HttpConstants._headerSign);
            String headerKey=hMap.get(HttpConstants._headerKey);
            System.out.println("************************params:"+params+"&&&&&&&&&&&&&&headerSign:"+headerSign+"***************headerKey:"+headerKey);
            if(MyStringUtil.isBlank(params)||MyStringUtil.isBlank(headerSign)||MyStringUtil.isBlank(headerKey)){
                System.out.println("params跟签名不为null");
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //params跟sign比较
            MD5 md5=new MD5();
            String md5Params=md5.GetMD5Code(params);
            System.out.println("*************签名加密后:"+md5Params);
            if(!headerSign.equalsIgnoreCase(md5Params)){
                System.out.println("签名不正确");
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //判断参数
            String cipherKey=headerKey.substring(0,8)+HttpConstants._key_end;
            //解密
            JSONObject pJsonObj=JSONObject.fromObject(Des3Util.decode(params,cipherKey));
            System.out.println("################解密后###########"+pJsonObj);
            //检查是否含有版本号
            if (!pJsonObj.containsKey(HttpConstants._paramsCode)) {
                System.out.println("appUsername is null !!! ");
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //版本号
            String paramsCode=pJsonObj.getString(HttpConstants._paramsCode);
            //检查是否含有用户名
            if (!pJsonObj.containsKey(HttpConstants._paramsName)) {
                System.out.println("appUsername is null !!! ");
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //用户名
            String appUsername=pJsonObj.getString(HttpConstants._paramsName);
            //检查是否含有密码
            if (!pJsonObj.containsKey(HttpConstants._paramsPsw)) {
                System.out.println("appPassword is null !!! ");
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //密码
            String appPassword=pJsonObj.getString(HttpConstants._paramsPsw);
            //检查是否含有时间戳
            if (!pJsonObj.containsKey(HttpConstants._paramsTime)) {
                System.out.println("timeStamp is null !!! ");
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //时间戳
            String timeStamp=pJsonObj.getString(HttpConstants._paramsTime);


            //判断参数
            if(MyStringUtil.isBlank(appUsername)||MyStringUtil.isBlank(appPassword)
                    ||MyStringUtil.isBlank(timeStamp)
                    ||MyStringUtil.isBlank(paramsCode)
                    ||!appUsername.equals(HttpConstants._paramsNameValue)
                    ||!appPassword.equals(HttpConstants._paramsPswValue)
                    ){
                out.print(CommResp.args_error_resp.toString());
                out.flush();
                return;
            }
            //解析params
            JSONObject json = JSONObject.fromObject(pJsonObj);
            Map paramsMap = new HashMap(req.getParameterMap());
            for (Object key : json.keySet())
            {
                paramsMap.put(key, json.get(key));
            }
            req = new ParameterRequestWrapper(req, paramsMap);
            //到这所有参数判断完毕
            req.setAttribute("parmasMap",paramsMap);
            chain.doFilter(req,resp);
            // 完成，封装加密参数放在response里。
            byte[] resultByte = resp.getResponseData();
            String result = new String(resultByte, HttpConstants.UTF_8);
            System.out.println("Filter result origin..{}  " + uri + ":{" + result + "}");
            if (MyStringUtil.isNoneEmpty(result)) {
                JSONObject resultObject = JSONObject.fromObject(result);
                if (resultObject.containsKey("data")) {
                    String data = resultObject.getString("data");
                    if (MyStringUtil.isNoneEmpty(data) && !data.equalsIgnoreCase("null")) {
                        data = Des3Util.encode(data, cipherKey);
                        resultObject.put("data", data);
                    }
                }
                resp.setContentLength(-1);
                // 然后
                out.print(resultObject.toString());
                out.flush();
                return;
            } else {
                out.print(CommResp.service_exception_resp.toString());
                out.flush();
                return;
            }

        }catch (Exception e){
            StringWriter stringWriter = new StringWriter();
            e.printStackTrace(new PrintWriter(stringWriter));
            System.out.println("#############################catch");
            out.print(CommResp.service_exception_resp.toString());
            out.flush();
            return;
        }
    }
    
    @Override
    public void destroy() {

    }
}
